# coding: utf-8

import logging
import re
import string
import xml.dom.minidom

log = logging.getLogger('dsMtlX_ResolveEditor')
from Katana import NodegraphAPI, DrawingModule, Utils

arnoldNodeTypeDict = {
    'aiRaySwitch': 'ray_switch_shader',
    'aiSwitch': 'switch_shader',
    'aiBump2d': 'bump2d',
    'aiBump3d': 'bump3d',
    'aiNormalMap':  'normal_map',
    'ramp':         'ramp_rgb',
    'file':         'image',

    # TODO:2017.12.13
    'blendColors':  'mix_rgba',
    'aiRange':      'range',
    'aiFacingRatio':'facing_ratio',
    'aiSubstract':  'subtract',
    'reverse':      'subtract',
    'aiColorToFloat': 'rgb_to_float',
 }
arnoldNodeAttrDict = {
    'specularIOR': 'specular_IOR',
#TODO(2018.03.01)，修正对 “IOR” 属性与“R”通道的误判，造成参数值不能正常传递
    'coatIOR': 'coat_IOR',
    'thinFilmIOR': 'thin_film_IOR',
     'outColor': 'out',
     'outColorR': 'out.r',
     'outColorG': 'out.g',
     'outColorB': 'out.g',
     'outColorA': 'out.a',

     'outValue': 'out',
     'outValueX': 'out.x',
     'outValueY': 'out.y',
     'outValueZ': 'out.z',
     'normalCamera': 'normal',
     'inputR': 'input.r',
     'inputG': 'input.g',
     'inputB': 'input.b',

 #bump2d
    'outNormal':   'out',
    'bumpValue': 'bump_map',
    'bumpDepth': 'bump_height',
 #image
    'colorGain': 'multiply',
    'colorOffset':'offset',


# TODO: 2017.11.3 假设当有alphaOffset参数调整时，仅当作bump贴图使用，out.a 代替 outAlpha
    'alphaGain':'multiply',
    'alphaOffset':'offset',
    'outAlpha': 'out',

 #ramp_rgb
    'colors':   'color',

# TODO: 2017.12.13
    'blender':  'mix',
    'color1':   'input1',
    'color2':   'input2',
    'aiFlipR':  'invert_x',
    'aiFlipG':  'invert_y',
    'aiFlipB':  'invert_z',
    'output':   'out'
                      }

bump2d_type = {
    "bump2d": "",
    "normal_map": "",
}


map_ramp_type = {
    "0": "v",
    "1": "u",
    "2": "diagonal",
    "3": "radial",
    "4": "circular",
    "5": "box",
    "6": "custom",
    "7": "custom",
    "8": "custom",
}
map_ramp_interp = {
    '0': '0',
    '1': '1',
    '2': '3',
    '3': '3',
    '4': '2',
    '5': '1',
    '6': '1'
}
map_mix_mode = {
    '0' : 'blend',
    '1' : 'add'
}
#TODO(2018.03.14), 修复mtoa和ktoa中 arnoldStandsurface 的 subsurface 参数类型不对应的错误
map_subsurface_type = {
    '0': 'diffusion',
    '1': 'randomwalk'
}

arnoldNodeAttrComp = {'R',
 'G',
 'B',
 'X',
 'Y',
 'Z'}

#TODO(2018.03.01)，修正对 “IOR” 属性与“R”通道的误判，造成参数值不能正常传递
IOR_ATTR_FILTER = ['specularIOR', 'thinFilmIOR', 'coatIOR']

MAT_NAME_SPACE = ''
MODE = ''



class KBase(object):

    def __init__(self, name, parent):

        self._name = name
        self._parent = parent
        self._node = None

        # print 'Name=%s, Parnt=%s, Type=%s' %(name, parent.getName(), ntype)

    def createNode(self, nType):
        if not NodegraphAPI.GetNode(self._name):
            with NodegraphAPI.InteractiveContext():
                self._node = NodegraphAPI.CreateNode(nType, self._parent)
        else:
            self._node = NodegraphAPI.GetNode(self._name)

    def setColor(self, r, g, b):
        DrawingModule.SetCustomNodeColor(self._node, r, g, b)

    def node(self):
        return self._node

    def setName(self):
        try:
            self.setValue('name', self._name)
        except:
            self._node.setName(self._name)

    def name(self):
        return self._name

    def setValue(self, param, value):
        self._node.getParameter(param).setValue(value, 0)

    def connect(self, sourParam, targPort):
        self._node.getOutputPort(sourParam).connect(targPort)

    def __str__(self):
        return self.name()


class CommonNode(KBase):

    def __init__(self, name, parent, nType):
        super(CommonNode, self).__init__(name, parent)

        self.createNode(nType)
        self.setName()

    def getInputPort(self, name):
        return self._node.getInputPort(name)

    def getOutputPort(self, name):
        return self._node.getOutputPort(name)

    def addInputPort(self, name):
        return self._node.addInputPort(name)

    def getNumInputPorts(self):
        return self._node.getNumInputPorts()

    def getInputPortByIndex(self, id):
        return self._node.getInputPortByIndex(id)

    def getOutputPortByIndex(self, id):
        return self._node.getOutputPortByIndex(id)


class MaterialAssign(CommonNode):
    def __init__(self, name, parent, nType):
        super(MaterialAssign, self).__init__(name, parent, nType)


    def setExpression(self, param, value):
        self._node.getParameter(param).setExpression(value)

    # def setCEL(self, param, value):
    #     self._node.getParameter(param).setExpression(value)


class NetworkMaterial(CommonNode):

    def __init__(self, name, parent, hasDisp):
        super(NetworkMaterial, self).__init__(name, parent, 'NetworkMaterial')


        self._node.getParameter('namespace').setValue(MAT_NAME_SPACE, 0)

        if MODE == '3delight':
            self._node.addShaderInputPort('dl', 'Surface')

            if hasDisp:
                self._node.addShaderInputPort('dl', 'Displacement')

        elif MODE == 'arnold':
            self._node.addShaderInputPort('arnold', 'Surface')

            if hasDisp:
                self._node.addShaderInputPort('arnold', 'Displacement')


        self.setColor(0, 0, 0)






class ArNode(KBase):
    global arnoldNodeTypeDict

    def __init__(self, name, parent, arNodeType, mtlXS_xml):
        super(ArNode, self).__init__(name, parent)

        self._origName = name


        # TODO: 兼容maya的name space
        if len(self._origName.split(':')) > 1:
            self._origName = self._origName.replace(':', '_')



        self._name = MAT_NAME_SPACE + '_' + self._origName

        # print '-------A---------%s' % self._name

        self._xml = mtlXS_xml
        self._type = self.getArNodeType(arNodeType)
        # self._dirtyParams = self.getDirtyParams(self._origName, self._xml)

        self.createNode('ArnoldShadingNode')
        self.setName()


    def createNode(self, nType):
        if not NodegraphAPI.GetNode(self._name):
            with NodegraphAPI.InteractiveContext():
                self._node = NodegraphAPI.CreateNode('ArnoldShadingNode', self._parent)


            self._nodeTypeAttr = self._node.getParameters().getChild('nodeType')




            indexInShaderList = getIndexInList(self._xml.getElementsByTagName('shader'), 'name', self._origName)
            shaderDirtyParams = self._xml.getElementsByTagName('shader')[indexInShaderList].getElementsByTagName('parameter')
            for param in shaderDirtyParams:
                if param.getAttribute('name') == 'i_bumpInterp':
                    shaderDirtyParams.remove(param)
                    self._type = 'normal_map'

                    coshaders = self._xml.getElementsByTagName('shader')[indexInShaderList].getElementsByTagName('coshader')
                    if len(coshaders):
                        for shd in coshaders:
                            if shd.getAttribute('name') == 'i_bumpValue':
                                shd.setAttribute('name', 'i_input')

            with NodegraphAPI.InteractiveContext():
                self._nodeTypeAttr.setValue(str(self._type), NodegraphAPI.GetCurrentTime(), False)
                self._node.checkDynamicParameters()

                #Fix: disable the two switch
                if self._type == 'normal_map':
                    # self.setValue('parameters.color_to_signed.enable', 1)
                    # self.setValue('parameters.color_to_signed.value', 0)
                    # self.setValue('parameters.tangent_space.enable', 1)
                    # self.setValue('parameters.tangent_space.value', 0)
                    pass
                #Fix1: 如果是_color贴图，自动将color_space改为sRGB
                # elif self._type == 'image':
                #     for param in shaderDirtyParams:
                #         paramName = str(param.getAttribute('name'))[2:]
                #         if str(param.getAttribute('type')) == 'filename':
                #             filename = param.getAttribute('value').split('/')[-1].split('.')[0].split('_')[-1]
                #
                #             if filename == 'color':
                #                 for param in shaderDirtyParams:
                #                     paramName = str(param.getAttribute('name'))[2:]
                #                     if paramName == 'colorSpace':
                #                         shaderDirtyParams.remove(param)
                #                         self.setValue('parameters.color_space.enable', 1)
                #                         self.setValue('parameters.color_space.value', 'sRGB')
                #             else:
                #                 for param in shaderDirtyParams:
                #                     paramName = str(param.getAttribute('name'))[2:]
                #                     if paramName == 'colorSpace':
                #                         shaderDirtyParams.remove(param)

                # Fix2: 如果是_color贴图，自动忽略color_space设置
                # elif self._type == 'image':
                #     for param in shaderDirtyParams:
                #         paramName = str(param.getAttribute('name'))[2:]
                #         if str(param.getAttribute('type')) == 'filename':
                #             for param in shaderDirtyParams:
                #                 paramName = str(param.getAttribute('name'))[2:]
                #                 if paramName == 'colorSpace':
                #                     shaderDirtyParams.remove(param)





            for param in shaderDirtyParams:
                paramName = str(param.getAttribute('name'))[2:]

                #TODO: 2018,1.5, 1.18, 修复 “IOR” 与 “R” 混淆的问题
                if paramName[-1] in arnoldNodeAttrComp and paramName not in IOR_ATTR_FILTER:
                    # print '-----------B---------%s' % paramName
                    paramName = ReformatParameter(paramName, True)
                    # print '-----------A---------%s' % paramName
                    continue
                if self._node.getParameter('parameters.%s' % ReformatParameter(paramName, False)):
                    paramName = ReformatParameter(paramName, False)
                elif arnoldNodeAttrDict.has_key(paramName):
                    paramName = arnoldNodeAttrDict[paramName]
                    # print '-----------A---------%s' %paramName

                paramGroup = self._node.getParameter('parameters.%s' %paramName)
                if not paramGroup:
                    print 'DISCARD TO SET PARAMETER [%s] FOR NODE [%s]' % (
                    paramName, self._node.getParameter('name').getValue(0))
                    continue
                print 'SETTING PARAMETER [%s] ON NODE [%s]' % (paramName, self._node.getParameter('name').getValue(0))
                self._node.getParameter('parameters.%s.enable' % paramName).setValue(1, NodegraphAPI.GetCurrentTime())


                dataType = str(param.getAttribute('type'))
                if dataType == 'color3' or dataType == 'float3':
                    # print '-----------------------------------'
                    # print self._type
                    #TODO: 2018.01.31
                    if self._type == 'mix_rgba':
                        if paramName == 'color1':
                            paramName = 'color2'
                        elif paramName == 'color2':
                            paramName = 'color1'

                    rParam = self._node.getParameter('parameters.%s.value.i0' % paramName)
                    gParam = self._node.getParameter('parameters.%s.value.i1' % paramName)
                    bParam = self._node.getParameter('parameters.%s.value.i2' % paramName)

                    if rParam is not None and gParam is not None and bParam is not None:
                        r, g, b = param.getAttribute('value').split(',')

                        self.setValue('parameters.%s.value.i0' % paramName, float(r))
                        self.setValue('parameters.%s.value.i1' % paramName, float(g))
                        self.setValue('parameters.%s.value.i2' % paramName, float(b))

                elif dataType == 'float':
                    if paramName == 'offset' or paramName == 'multiply':
                        # TODO: 2017.11.08 如果属性名为 offset，并且为 float， 那么对应 ktoa 属性为 i0
                        # TODO: 2018.02.28，如果 maya file 节点的 alphaGain 或 alphaOffset 有设置，
                        # 则在 katana 中转化为 multiply 和 offset 参数
                        rParam = self._node.getParameter('parameters.%s.value.i0' % paramName)
                        gParam = self._node.getParameter('parameters.%s.value.i1' % paramName)
                        bParam = self._node.getParameter('parameters.%s.value.i2' % paramName)
                        if rParam is not None:
                            self.setValue('parameters.%s.value.i0' % paramName, float(param.getAttribute('value')))
                        if gParam is not None:
                            self.setValue('parameters.%s.value.i1' % paramName, float(param.getAttribute('value')))
                        if bParam is not None:
                            self.setValue('parameters.%s.value.i2' % paramName, float(param.getAttribute('value')))
                    else:
                        self.setValue('parameters.%s.value' % paramName, float(param.getAttribute('value')))

                elif dataType == 'integer':

                    if self._type == 'ramp_rgb' or self._type == 'ramp_float':
                        self.setValue('parameters.%s.value' % paramName, map_ramp_type[param.getAttribute('value')])

                    # TODO : mix shader
                    elif self._type == 'mix_shader':
                        self.setValue('parameters.%s.value' % paramName, map_mix_mode[param.getAttribute('value')])
                    else:
                        # TODO(2018.03.14), 修复mtoa和ktoa中 arnoldStandsurface 的 subsurface 参数类型不对应的错误，maya
                        #中是整形，katana中是字符串
                        try:
                            self.setValue('parameters.%s.value' % paramName, int(param.getAttribute('value')))
                        except:
                            self.setValue('parameters.%s.value' % paramName, map_subsurface_type[(param.getAttribute('value'))])

                # TODO: 2018.01.18, 如果image的color_space为默认值，则强制为 linear
                # TODO: 2018.02.26, 无论是否为默认值，均强制修改 image的 color_sapce为 linear
                elif dataType == 'string':
                    # if str(param.getAttribute('value')) != 'Raw':
                    #     self.setValue('parameters.%s.value' % paramName, str(param.getAttribute('value')))
                    # else:
                    #     self.setValue('parameters.%s.value' % paramName, 'linear')
                    self.setValue('parameters.%s.value' % paramName, 'linear')

                elif dataType == 'filename':
                    self.setValue('parameters.%s.value' % paramName, str(param.getAttribute('value')))

                elif dataType == 'boolean':
                    if param.getAttribute('value') == 'False':
                        self.setValue('parameters.%s.value' % paramName, 0)
                    else:
                        self.setValue('parameters.%s.value' % paramName, 1)

                elif dataType == 'Color3ArrayAttribute' and self._type == 'ramp_rgb':
                    self.setRampValue(shaderDirtyParams)

                elif dataType == 'FloatArrayAttribute' and self._type == 'ramp_float':
                    continue

                else:
                    print 'TODO: ', paramName, dataType

        else:
            self._node = NodegraphAPI.GetNode(self._name)


    def getArNodeType(self, arType):
        tp = ''

        if arnoldNodeTypeDict.has_key(arType):
            tp = arnoldNodeTypeDict[str(arType)]
        elif str(arType)[:2] == 'ai':
            tp = ReformatParameter(str(arType)[2:], False)
        else:
            tp = ReformatParameter(str(arType), False)

        return tp


    def getDirtyParams(self, nodeName, xml):
        dirtyParams = {}

        indexInShaderList = getIndexInList(xml.getElementsByTagName('shader'), 'name', nodeName)
        shaderDirtyParams = xml.getElementsByTagName('shader')[indexInShaderList].getElementsByTagName('parameter')
        if len(shaderDirtyParams):
            for param in shaderDirtyParams:
                name = param.getAttribute('name')
                type = param.getAttribute('type')
                value = param.getAttribute('value')
                dirtyParams[name] = [type, value]

        return dirtyParams


    def setRampValue(self, param):
        tp = '0'
        interp = '1'

        rampColorList = list()
        positionsList = list()
        colorByPosition = dict()
        for dirtyParam in param:
            if dirtyParam.getAttribute('name') == 'i_colors':
                i_colors = str(dirtyParam.getAttribute('value')).split(' ')
                for color in i_colors:
                    color = color.split(',')
                    rampColorList.append(tuple((float(f) for f in color)))

            if dirtyParam.getAttribute('name') == 'i_colorPositions':
                i_colorPositions = str(dirtyParam.getAttribute('value')).split(',')
                positionsList = [float(f) for f in i_colorPositions]

            if dirtyParam.getAttribute('name') == 'i_type':
                tp = map_ramp_type[dirtyParam.getAttribute('value')]

            if dirtyParam.getAttribute('name') == 'i_interpolation':
                interp = map_ramp_interp[dirtyParam.getAttribute('value')]

        for i in range(len(positionsList)):
            colorByPosition[positionsList[i]] = rampColorList[i]

        # print colorByPosition
        with NodegraphAPI.InteractiveContext():
            rampParameter = self._node.getParameter('parameters')
            self.setRampColor(tp, interp, rampParameter, colorByPosition)

        # for child in self._node.getParameter('parameters.position.value').getChildren():
        #     print child
        #     print 'this knot value is ' + str(child.getValue(0))
        #
        # for child in self._node.getParameter('parameters.color.value').getChildren():
        #     print child
        #     print 'this color value is ' + str(child.getValue(0))

    def setRampColor(self, tp, interp, rampParameter, colorByPosition):
        positions = sorted(colorByPosition)
        n = len(positions)

        Utils.UndoStack.OpenGroup('Set %d Colors on %s' % (n, rampParameter.getFullName()))
        try:
            # TODO: setting ramp type
            rampParameter.getChild('type').setValue(tp, 0)

            ramp = rampParameter.getChild('ramp')
            ramp.getChild('enable').setValue(1, 0)
            rampValue = ramp.getChild('value')
            rampValue.setValue(n + 2, 0)

            # interValue =
            interpParameter = rampParameter.getChild('interpolation')
            interpParameter.getChild('enable').setValue(1, 0)
            interpValueParameter = interpParameter.getChild('value')
            interpValueParameter.resizeArray(n + 2)
            interpValueParameter.getChildByIndex(0).setValue(interp, 0)

            positonParameter = rampParameter.getChild('position')
            positonParameter.getChild('enable').setValue(1, 0)
            positonValueParameter = positonParameter.getChild('value')
            positonValueParameter.resizeArray(n + 2)
            positonValueParameter.getChildByIndex(0).setValue(positions[0], 0)

            for i, position in enumerate(positions):
                interpValueParameter.getChildByIndex(1 + i).setValue(interp, 0)
                positonValueParameter.getChildByIndex(1 + i).setValue(position, 0)
            # #
            interpValueParameter.getChildByIndex(n + 1).setValue(interp, 0)
            positonValueParameter.getChildByIndex(n + 1).setValue(positions[-1], 0)

            # colorsParameterName = '%s_Colors' % parameterName
            colorsParameter = rampParameter.getChild('color')
            colorsParameter.getChild('enable').setValue(1, 0)
            colorsValueParameter = colorsParameter.getChild('value')
            colorsValueParameter.resizeArray(3 * (n + 2))
            for i, position in enumerate(positions):
                r, g, b = colorByPosition[position]
                colorsValueParameter.getChildByIndex(3 + 3 * i).setValue(r, 0)
                colorsValueParameter.getChildByIndex(3 + 3 * i + 1).setValue(g, 0)
                colorsValueParameter.getChildByIndex(3 + 3 * i + 2).setValue(b, 0)
            #
            r, g, b = colorByPosition[positions[0]]
            colorsValueParameter.getChildByIndex(0).setValue(r, 0)
            colorsValueParameter.getChildByIndex(1).setValue(g, 0)
            colorsValueParameter.getChildByIndex(2).setValue(b, 0)
            r, g, b = colorByPosition[positions[-1]]
            colorsValueParameter.getChildByIndex(3 * (n + 1)).setValue(r, 0)
            colorsValueParameter.getChildByIndex(3 * (n + 1) + 1).setValue(g, 0)
            colorsValueParameter.getChildByIndex(3 * (n + 1) + 2).setValue(b, 0)
        finally:
            Utils.UndoStack.CloseGroup()

    def connect(self, id, targetParam):
        self._node.getOutputPortByIndex(id).connect(targetParam)



def ResolveMtlXS(gnode, filePath, location, matLocation, selMode):
    global MODE
    global MAT_NAME_SPACE


    log.info('Mode is: ' + selMode)
    log.info('Reading ' + filePath)
    mtlXS_xml = xml.dom.minidom.parse(filePath)
    if len(mtlXS_xml.getElementsByTagName('materialx')) == 0:
        log.warning('File is not a valid MtlX file.')
        return
    MAT_NAME_SPACE = matLocation
    MODE = selMode


    #建立 merge 节点
    mtlXmerge = CommonNode('%s_Merge' %gnode.getName(), gnode, 'Merge')
    mtlXmerge.setColor(0.569, 0.449, 0.089)
    mtlXmerge.addInputPort('i0').connect(gnode.getSendPort('in'))



    #收集 shading group
    matList = mtlXS_xml.getElementsByTagName('material')

    #收集 shader
    shaderNameToShaderType = dict()
    nodes = mtlXS_xml.getElementsByTagName('shader')
    for node in nodes:
        nodeName = node.getAttribute('name')
        shaderType = node.getAttribute('shaderprogram')
        shaderNameToShaderType[nodeName] = shaderType

    maNodes = list()
    grpNodes = list()
    objSettingsNodes = list()
    x = 0
    for mat in matList:
        x += 1

        shaderName_full = MAT_NAME_SPACE + '_' + str(mat.getAttribute('name'))
        assignments = GetAssignments(mat.getElementsByTagName('collection'), gnode)

        #建立 Material group
        grpShadingGrp = CommonNode('%s_GRP' %shaderName_full, gnode, 'Group')
        grpShadingGrp.setColor(0.17, (x + 0.2) / (len(matList) * 2), 0.29)
        grpNodeRootParam = grpShadingGrp.node().getParameters()
        shdIntTeleParam = grpNodeRootParam.createChildGroup('ShadingUI')

        #建立 NetworkShader
        hasDisp = len(mat.getElementsByTagName('shaderref')) > 1
        networkMatHead = NetworkMaterial(shaderName_full, grpShadingGrp.node(), hasDisp)
        if hasDisp:
            involvedNodes = []
            dispShaderName = str(mat.getElementsByTagName('shaderref')[1].getAttribute('name'))
            indexInShaderList = getIndexInList(nodes, 'name', dispShaderName)
            dispCoShaders = nodes[indexInShaderList].getElementsByTagName('coshader')
            for coshader in dispCoShaders:
                # if coshader.getAttribute('shader') not in involvedNodes:
                involvedNodes.append(coshader.getAttribute('shader'))

            if len(involvedNodes) > 0:
                traverseNodeArray(involvedNodes, nodes)
            for coshader in involvedNodes:
                # disCoshaderName = str(coshader.getAttribute("shader"))
                # print '--------------------%s' %coshader
                disCoShader = ArNode(str(coshader),
                                     grpShadingGrp.node(),
                                     shaderNameToShaderType[coshader],
                                     mtlXS_xml)
                if disCoShader.name() == MAT_NAME_SPACE + '_' + str(dispCoShaders[0].getAttribute('shader')):
                    # print '-----ABABAB----------%s' %disCoShader.name()
                    # # dispSh = disCoShader.node()
                    # print '-----BNBNVN----------%s' %str(dispSh)
                    disCoShader.node().getOutputPortByIndex(0).connect(networkMatHead.getInputPortByIndex(1))
            # dispSh = NodegraphAPI.GetNode(dispShaderName)
            #     disCoShader.connect(0, networkMatHead.node().getInputPortByIndex(1))

                # shdIntTeleParam = grpNodeRootParam.createChildGroup('DisplacementUI')
                # CreateTeleParam(grpShadingGrp.node().getParameter('DisplacementUI'),
                #                 disCoShader.node().getParameter('parameters.multiply'))
                # CreateTeleParam(grpShadingGrp.node().getParameter('DisplacementUI'),
                #                 disCoShader.node().getParameter('parameters.offset'))
            # print '-----------------------%s' %dispShaderName
            for nd in nodes:
                # TODO: 2017.12.18
                if nd.getAttribute("shaderprogram") == 'displacementShader' and nd.getAttribute("name") == dispShaderName:
                    nodes.remove(nd)
            # TODO: 2018.03.02, 取消根据是否有置换材质而自动添加 ArnoldObjectSettings 节点，由渲染部门自行添加
            # objSetNode = CommonNode(MAT_NAME_SPACE + '_' + '%s_DispObjSet' % str(mat.getAttribute('name'))[:-2],
            #                         gnode, 'ArnoldObjectSettings')
            # objSetNode.setValue('CEL', assignments)
            # objSetNode.setValue('args.arnoldStatements.smoothing.enable', 1)
            # objSetNode.setValue('args.arnoldStatements.smoothing.value', 1)
            # objSetNode.setValue('args.arnoldStatements.subdiv_type.enable', 1)
            # objSetNode.setValue('args.arnoldStatements.subdiv_type.value', 'catclark')
            # objSetNode.setValue('args.arnoldStatements.iterations.enable', 1)
            # objSetNode.setValue('args.arnoldStatements.iterations.value', 0)
            # objSetNode.setColor(0.17, (x + 0.2) / (len(matList) * 2), 0.29)
            # objSettingsNodes.append(objSetNode)


        #连接 networkShader 到 merger node
        mergeNextPort = mtlXmerge.getNumInputPorts()
        mtlXmerge.addInputPort('i' + str(mergeNextPort))
        networkMatHead.connect('out', mtlXmerge.getInputPortByIndex(mtlXmerge.getNumInputPorts() - 1))


        #建立 Surface shader
        surfaceShaderName = str(mat.getElementsByTagName('shaderref')[0].getAttribute('name'))
        surfaceShader = ArNode(surfaceShaderName,
                               grpShadingGrp.node(),
                               shaderNameToShaderType[surfaceShaderName],
                               mtlXS_xml)
        surfaceShader.connect(0, networkMatHead.node().getInputPortByIndex(0))

        listOfShParams = surfaceShader.node().getParameters().getChild('parameters')
        # for i, p in enumerate(listOfShParams.getChildren()):
        #     if i < len(listOfShParams.getChildren()) - 1:
        #         CreateTeleParam(grpShadingGrp.node().getParameter('ShadingUI'), p)

        #建立 Surface coshader
        involvedNodes = []
        indexInShaderList = getIndexInList(nodes, 'name', surfaceShaderName)
        surfaceCoShaders = nodes[indexInShaderList].getElementsByTagName('coshader')
        for coshader in surfaceCoShaders:
            if coshader.getAttribute('shader') not in involvedNodes:
                involvedNodes.append(coshader.getAttribute('shader'))
        if len(involvedNodes) > 0:
            traverseNodeArray(involvedNodes, nodes)
        for shadingNodeName in involvedNodes:
            shadingNodeClass = ArNode(str(shadingNodeName),
                                      grpShadingGrp.node(),
                                      shaderNameToShaderType[shadingNodeName],
                                      mtlXS_xml)
            # print '-----HERE----------%s' %shaderNameToShaderType[shadingNodeName]
        # print '----------------------Co Shader'
        # print involvedNodes
        grpNodes.append(grpShadingGrp.node())



        #建立 Material Assign
        maNodeAssign = MaterialAssign('%s_Assignment' %shaderName_full, gnode, 'MaterialAssign')
        maNodeAssign.setColor(0.17, (x + 0.2) / (len(matList) * 2), 0.29)
        maNodeAssign.setExpression('args.materialAssign.value', "scenegraphLocationFromNode(getNode('%s'))" % shaderName_full)
        maNodeAssign.setValue('CEL', assignments)
        maNodes.append(maNodeAssign)

        #自动排列节点
        DrawingModule.AutoPositionNodes(grpShadingGrp.node().getChildren())

    for shadingNodeElement in nodes:
        restoreConnections(shadingNodeElement, nodes)


    #建立 gnode merge materialAssign 之间的连接
    gnode.getReturnPort('out').connect(mtlXmerge.getOutputPortByIndex(0))
    if len(maNodes):
        mtlXmerge.connect('out', maNodes[0].getInputPort('input'))
        for i in range(len(maNodes) - 1):
            maNodes[i].connect('out', maNodes[i + 1].getInputPort('input'))

        maNodes[-1].connect('out', gnode.getReturnPort('out'))

    if len(objSettingsNodes):
        maNodes[-1].connect('out', objSettingsNodes[0].getInputPort('input'))
        for i in range(len(objSettingsNodes) - 1):
            objSettingsNodes[i].connect('out', objSettingsNodes[i + 1].getInputPort('input'))

        objSettingsNodes[-1].connect('out', gnode.getReturnPort('out'))

    #自动排列节点
    DrawingModule.AutoPositionNodes(gnode.getChildren())
    for matGrp in grpNodes:
        DrawingModule.AutoPositionNodes(matGrp.getChildren())


def CreateTeleParam(parentParam, targetParam):
    teleParam = parentParam.createChildString('%sTeleParam' % targetParam.getName(), '')
    teleParam.setExpression('getParam("%s").param.getFullName()' % targetParam.getFullName())
    teleParam.setHintString(repr({'widget': 'teleparam'}))


def restoreConnections(shadingNode, nodes):
    global arnoldNodeAttrDict

    indexInShaderList = getIndexInList(nodes, 'name', str(shadingNode.getAttribute('name')))
    surfaceCoShaders = nodes[indexInShaderList].getElementsByTagName('coshader')
    # print '------Node=%s' % (MAT_NAME_SPACE + '_' + str(shadingNode.getAttribute('name')))

    targetName = MAT_NAME_SPACE + '_' + str(shadingNode.getAttribute('name'))
    # TODO: 兼容 maya namespace
    if len(targetName.split(':')) > 1:
        targetName = targetName.replace(':', '_')
    targetNode = NodegraphAPI.GetNode(targetName)

    for coshader in surfaceCoShaders:
        # print '--------A---------%s' %coshader.getAttribute('shader')
        # TODO:
        sourceShader = MAT_NAME_SPACE + '_' + str(coshader.getAttribute('shader'))
        if len(str(coshader.getAttribute('shader')).split(':')) > 1:
            sourceShader = MAT_NAME_SPACE + '_' + str(coshader.getAttribute('shader')).replace(':', '_')



        sourceAttr = str(coshader.getAttribute('aovset'))[2:]
        targetAttr = str(coshader.getAttribute('name'))[2:]



        sourceNode = NodegraphAPI.GetNode(sourceShader)
        # print '------B-----%s' % sourceShader
        # print '------B--NODE--%s' % sourceNode


        if targetAttr[-1:] in arnoldNodeAttrComp:
            targetAttr = ReformatParameter(targetAttr, True)
        if sourceNode.getParameter('parameters.%s' % ReformatParameter(sourceAttr, False)) != None:
            sourceAttr = ReformatParameter(sourceAttr, False)
        elif arnoldNodeAttrDict.has_key(sourceAttr):
            sourceAttr = arnoldNodeAttrDict[sourceAttr]
        if targetNode.getParameter('parameters.%s' % ReformatParameter(targetAttr, False)) != None:
            targetAttr = ReformatParameter(targetAttr, False)
        elif arnoldNodeAttrDict.has_key(targetAttr):
            targetAttr = arnoldNodeAttrDict[targetAttr]

        print 'CONNECT [%s.%s] TO [%s.%s].' %(sourceShader, sourceAttr, targetNode.getName(), targetAttr)

        if sourceAttr != 'outUV' and sourceNode.getParameters().getChild('nodeType').getValue(0) == 'place2dTexture':
            continue

        elif sourceAttr == 'worldInverseMatrix[0]' and sourceNode.getParameters().getChild('nodeType').getValue(0) == 'place3dTexture':
            sourceNode.getOutputPort('o_' + sourceAttr[:-3]).connect(targetNode.getInputPort(targetAttr))

        elif targetAttr[-1:] == 'R' or targetAttr[-1:] == 'G' or targetAttr[-1:] == 'B':
            sourceNode.getOutputPort(sourceAttr).connect(targetNode.getInputPort(targetAttr[:-1]))

        elif 'colorEntryList' in targetAttr:
            # print '----------------------- %s, %s' %(sourceNode.getName(), sourceAttr)
            # print '----------------------- %s, %s' %(targetNode.getName(), targetAttr)
            sourceNode.getOutputPort(sourceAttr).connect(targetNode.getInputPort('color_Colors'))

        elif sourceNode.getOutputPort(sourceAttr):

            # print '----------------------- %s, %s' %(sourceNode.getName(), sourceAttr)
            # print '----------------------- %s, %s' %(targetNode.getName(), targetAttr)
            sourceNode.getOutputPort(sourceAttr).connect(targetNode.getInputPort(targetAttr))
            # print '------------------finished.'

        else:
            log.warning('Failed to restore connection for ' + sourceAttr + ' on [' + sourceNode.getName() + ']')


def GetAssignments(collectionTag, gnode):
    assignments = []

    if len(collectionTag):
        for collection in collectionTag:
            collAdd = collection.getElementsByTagName('collectionadd')
            for coll in collAdd:
                geomAdd = str(coll.getAttribute('geom')).split(', ')
                assignments.extend(geomAdd)

    if len(assignments):
        assignments = ['%s%s' % (gnode.getParameter('location').getValue(0), y) for y in assignments]


    return str(string.join(assignments))


def ReformatParameter(stringParameter, isComponent):
    tempSplit = [ a for a in re.split('([A-Z][a-z]*\\d*)', stringParameter) if a ]
    combineString = ''
    for partialString in tempSplit:
        partialString = partialString.lower()
        if combineString == '':
            combineString = partialString
        else:
            combineString += '_' + partialString

    if isComponent:
        attrComponent = combineString.rsplit('_', 1)
        return str('.').join(attrComponent)
    else:
        return combineString


def getIndexInList(sourceList, attribute, valueToFind):
    indexForAttribute = 0
    for obj in sourceList:
        if obj.getAttribute(attribute) == valueToFind:
            indexForAttribute = sourceList.index(obj)

    return indexForAttribute


def RestoreToDefault(gnode):
    children = gnode.getChildren()
    for child in children:
        child.delete()


def traverseNodeArray(involvedNodes, nodes):
    for node in involvedNodes:
        nodeIndex = getIndexInList(nodes, 'name', node)
        currNodeCoshaders = nodes[nodeIndex].getElementsByTagName('coshader')
        if len(currNodeCoshaders) > 0:
            indexInShaderList = getIndexInList(nodes, 'name', node)
            nodeCoShaders = nodes[indexInShaderList].getElementsByTagName('coshader')
            for con in nodeCoShaders:
                if con.getAttribute('shader') not in involvedNodes:
                    involvedNodes.append(con.getAttribute('shader'))